#pragma once

#include "my_defs.h"
#include "my_atomic.h"
#include "my_queue.h"

/**
 * @brief my_buf设计、使用及注意事项
 * 
 * my_buf包含了my_buf_data, my_buf, my_buf_chain三个对象.
 * 
 * my_buf_data负责管理最底层的数据缓存区.
 * my_buf管理对应buf_data中的可读数据区和可写数据区,
 * - 同时my_buf可能指向同一个my_buf_data, 不同my_buf可以维护自己的数据消费情况
 * my_buf_chain本质上是一个简单的queue, 管理多个my_buf, 用于实现数据的流式管理,
 * - 它是一个单生产者单消费者的结构, 从尾部写入, 从头部读取.
 * - 需要注意的是my_buf_chain是一个非线程安全的结构, 多线程间读写需自行实现线程安全.
 * - my_buf_chain未实现消息通知机制, 需使用者自行实现.
 * 
 * 注意: my_buf_data和my_buf使用引用计数进行管理, 使用完毕后一定要进行free.
 * - 注意: 将my_buf_data托管给my_buf后也需要进行free. 因为my_buf会对my_buf_data做hold操作.
 * - 注意: 将my_buf托管给my_buf_chain后也需要进行free. 因为my_buf_chain会对my_buf做hold操作.
 * 
 * 
 * my_buf_data使用指南:
 * my_buf_data在创建时就将对应的refer设置为1
 * - 通过hold操作可以将它的引用计数+1, 而通过free会对引用计数-1, 当引用计数为0时将被释放.
 * - 将my_buf_data托管给my_buf管理时, my_buf会对my_buf_data的引用计数+1.
 * - 需要注意的是: 
 * ```
 *   function() {
 *        // buf_data在创建时, 引用计数为1.
 *        my_buf_data_t *buf_data = my_buf_data_alloc();
 *        // 将buf_data托管给buf对象管理, 在my_buf_alloc中对buf_data执行了hold操作, buf_data引用计数为2.
 *        my_buf_t *buf = my_buf_alloc(buf_data, buf_data->data, buf_data->data);
 *        // 注意: 使用完毕后一定要释放, 此时buf_data的引用计数减为1.
 *        my_buf_data_free(buf_data);
 *        // 注意: 使用完毕后一定要释放, 此时buf的引用计数减少为0
 *        // 会同时释放buf, 并对管理的buf_data进行free.
 *        // 此时buf_data的引用计数减为0, buf_data最终完成释放.
 *        my_buf_free(buf);
 *   }
 * ```
 * 
 * 
 * my_buf使用指南:
 * 通过my_buf_alloc创建的my_buf结构, 会对传入的buf_data执行hold操作.
 * 通过my_buf_alloc_ext/my_buf_aligned_alloc_ext创建的结构,
 * - 会创建对应的buf_data, 并将它的引用计数设置为1.
 * - 在alloc_ext中, 先通过buf_alloc创建buf, 将它交给my_buf进行管理, 再对my_buf_data进行了free.
 * 当my_buf托管给my_buf_chain后, my_buf在使用完毕后, 需要对my_buf进行free.
 * ```
 *    function() {
 *        // buf_data->refer == 1
 *        my_buf_data_t *buf_data = my_buf_data_alloc();
 * 
 *        // buf_data->refer == 2, buf->refer == 1
 *        my_buf_t *buf = my_buf_alloc(buf_data, buf_data->data, buf_data->data);
 * 
 *        // buf_data->refer == 1, buf->refer == 1
 *        my_buf_data_free(buf_data);
 * 
 *        my_buf_chain_t *buf_chain = my_buf_chain_alloc();
 *        // buf_data->refer == 1, buf->refer == 2
 *        my_buf_chain_enqueue(chain, buf);
 * 
 *        // buf_data->refer == 1, buf->refer == 1
 *        my_buf_free(buf_data);
 * 
 *        // buf_data->refer == 0, buf->refer == 0, 均进行释放.
 *        my_buf_chain_free();
 *    }
 * ```
 * 
 * my_buf_chain使用指南
 * my_buf_chain是一个单向的queue, 使用enqueue将buf追加到chain的尾部,
 * 使用dequeue返回chain头部的第一个buf.
 * - enqueue会导致buf的refer + 1, 而dequque不会修改buf的refer.
 * - 通过dequeue获取的buf在使用完毕后应该主动调用free.
 * 
 * 
 * my_buf_chain流式读写

 * my_buf_chain_first/ my_buf_chain_next/ my_buf_chain_consume
 * 通过my_buf_chain_first返回第一个可读的buf,配合my_buf_chain_next可顺序遍历chain中的数据.
 * 最后通过my_buf_chain_consume可将chain中的数据消费掉.
 * 
 * my_buf_chain_last: 返回最后一个buf, 这通常是最后一个可写buf.
 * 将数据写入该buf后只需要简单的移动buf的end指针即可.
 * (如果可写空间不足, 需要append新的buf)
 * 
 * 
 * chain_copy:
 * 
 * my_buf_chain_copy/copy_n: 对buf_chain中的数据进行拷贝,
 * 新buf_chain除了复用底层的buf_data外，其余的结构都是新创建的.
 * 通过copy接口可实现多个读者消费同一份数据的目的.
 * 
 */


typedef struct {
    my_atomic_int64_t               refer;
    char                            *data;
    size_t                          size;
    unsigned                        aligned:1;
    unsigned                        last:1;
} my_buf_data_t;

my_buf_data_t *my_buf_data_alloc(size_t size);

my_buf_data_t *my_buf_data_aligned_alloc(size_t size);

void my_buf_data_free(my_buf_data_t *buf_data);

void my_buf_data_hold(my_buf_data_t *buf_data);



typedef struct {
    my_atomic_int64_t               refer;
    my_buf_data_t                   *data;
    char                            *data_end;  // space end in buf data
    char                            *start;     // start in buf data
    char                            *end;       // end in buf data
    char                            *pos;       // consumer pos
    my_queue_t                      queue;
} my_buf_t;

my_buf_t *my_buf_alloc(my_buf_data_t *buf_data, char *start, char *end);

my_buf_t *my_buf_alloc_ext(size_t size);

my_buf_t *my_buf_aligned_alloc_ext(size_t size);

void my_buf_free(my_buf_t *buf);

void my_buf_hold(my_buf_t *buf);

uint32_t my_buf_crc32(my_buf_t *buf);



typedef struct {
    my_queue_t                      head;
} my_buf_chain_t;

my_buf_chain_t *my_buf_chain_alloc();

void my_buf_chain_free();

// will call buf_hold for buf
void my_buf_chain_enqueue(my_buf_chain_t *chain, my_buf_t *buf);

// no not call buf_free, the user should release it.
my_buf_t *my_buf_chain_dequeue(my_buf_chain_t *chain);

void my_buf_chain_consume(my_buf_chain_t *chain, size_t n);

void my_buf_chain_copy(my_buf_chain_t *dest, const my_buf_chain_t *src);

void my_buf_chain_copy_n(my_buf_chain_t *dest, const my_buf_chain_t *src,
    size_t offset, size_t len);

my_buf_t *my_buf_chain_last(my_buf_chain_t *chain);

// return first readable buf
my_buf_t *my_buf_chain_first(my_buf_chain_t *chan);

// return next readable buf at the cur buf.
my_buf_t *my_buf_chain_next(my_buf_chain_t *chain, my_buf_t *cur);

size_t my_buf_chain_total_bytes(my_buf_chain_t *chain);

uint32_t my_buf_chain_crc32(my_buf_chain_t *chain);